﻿using System;
using Microsoft.Xna.Framework;
using Tomahawk.Runtime.Rendering.Particles;
using System.Xml.Serialization;
using Tomahawk.Runtime.Rendering.LightningBolts;
using Tomahawk.Runtime.Scene;
using Tomahawk.Serialization;
using Tomahawk.Serialization.SerialBoost;
using Tomahawk.Runtime.Resources;

namespace Tomahawk.Runtime.Logic
{
    public class XLightningBoltComponent : XRenderableComponent
    {
        #region LightningBoltEmitter

        public class LightningBoltEmitter
        {
            #region Serializable Properties

            [XmlAttribute("pool")]
            public ResourceManager.ResourcePool ResourcePool = ResourceManager.ResourcePool.GameState;

            [XmlElement("Settings")]
            public string settings;
            
            [XmlElement("Enabled")]
            public bool enabled = false;
            
            [XmlElement("StartPoint")]
            public Vector3 startPoint = Vector3.Zero;
            
            [XmlElement("EndPoint")]
            public Vector3 endPoint = Vector3.Zero;

            [XmlElement("RenderGroups")]
            public string RenderGroups
            {
                get { return renderGroups; }
                set
                {
                    renderGroups = value;
                    if (sceneNode != null)
                    {
                        sceneNode.RenderGroupNames = this.RenderGroups;
                    }
                }
            }

            #endregion

            #region Properties

            protected string renderGroups = "Color";

            private SceneNode sceneNode = null;

            private LightningBolt lightningBolt;

            [XmlIgnore()]
            public LightningBolt LightningBolt { get { return lightningBolt; } }

            [XmlIgnore()]
            public bool IsReady { get { return lightningBolt != null && lightningBolt.IsReady; } }

            public Vector3 Source
            {
                get { return lightningBolt != null ? lightningBolt.Source : Vector3.Zero; }
                set { if (lightningBolt != null) lightningBolt.Source = value; }
            }

            public Vector3 Destination
            {
                get { return lightningBolt != null ? lightningBolt.Destination : Vector3.Zero; }
                set { if (lightningBolt != null) lightningBolt.Destination = value; }
            }

            #endregion

            #region Initialization and Update

            public void Initialize(SceneNode node)
            {
                if (node != null)
                {
                    this.lightningBolt = new LightningBolt(startPoint, endPoint, Vector3.Forward, settings, this.ResourcePool);
                    this.sceneNode = node.CreateChildSceneNode();
                    this.sceneNode.Attach(this.lightningBolt);
                    this.sceneNode.RenderGroupNames = this.RenderGroups;
                }
            }

            public void Update(ref Matrix worldMatrix, float elapsedTime)
            {
                lightningBolt.Enabled = enabled;

                if (enabled)
                {
                    Matrix localMatrix;
                    Matrix.Invert(ref worldMatrix, out localMatrix);

                    Vector3 cameraForward = Engine.Instance.CameraManager.ActiveCamera.ViewVector;
                    Vector3 localCameraForward = Vector3.Zero;
                    Vector3.TransformNormal(ref cameraForward, ref localMatrix, out localCameraForward);

                    lightningBolt.CameraForward = localCameraForward;
                    lightningBolt.Update(elapsedTime);
                }
            }
            #endregion

        }
        #endregion

        #region Serializable Properties

        [XmlElement("Emitters")]
        public SerializableList<LightningBoltEmitter> emitters = new SerializableList<LightningBoltEmitter>();

        protected float timeout = -1.0f;

        #endregion

        #region Properties
        [XmlIgnore]
        public bool Enabled
        {
            get
            {
                bool result = true;
                for (int emitterIdx = 0; emitterIdx < emitters.Count; ++emitterIdx)
                {
                    result &= emitters[emitterIdx].enabled;
                }
                return result;
            }

            set
            {
                for (int emitterIdx = 0; emitterIdx < emitters.Count; ++emitterIdx)
                {
                    emitters[emitterIdx].enabled = value;
                }
            }
        }
        #endregion

        public XLightningBoltComponent()
        {
            UpdateRequired = true;
        }

        public void SetTimeout(float elapsedTime)
        {
            timeout = elapsedTime;
        }

        protected override bool checkResourcesReady()
        {
            bool lightningReady = true;
            for (int emitterIdx = 0; emitterIdx < emitters.Count; ++emitterIdx)
            {
                lightningReady &= emitters[emitterIdx].IsReady;
            }

            return base.checkResourcesReady() && lightningReady;
        }

        protected override void OnInitialize()
        {
            base.OnInitialize();

            for (int emitterIdx = 0; emitterIdx < emitters.Count; ++emitterIdx)
            {
                emitters[emitterIdx].Initialize(this.SceneNode);
            }
        }

        protected override void OnPostBeginPlay()
        {
            base.OnPostBeginPlay();
        }

        protected override void OnUpdate(float elapsedTime)
        {
            base.OnUpdate(elapsedTime);

            if (timeout > 0.0f)
            {
                timeout -= elapsedTime;
                if (timeout <= 0.0f)
                {
                    Enabled = false;
                }
            }

            Matrix worldMatrix = SceneNode.WorldMatrix;

            for (int emitterIdx = 0; emitterIdx < emitters.Count; ++emitterIdx)
            {
                emitters[emitterIdx].Update(ref worldMatrix, elapsedTime);
            }
        }
    }
}

